%% @author Mochi Media <dev@mochimedia.com>
%% @copyright 2010 Mochi Media <dev@mochimedia.com>

%% @doc Supervisor for the yzb application.

-module(yzb_sup).
-author("Mochi Media <dev@mochimedia.com>").

-behaviour(supervisor).

%% External exports
-export([start_link/0, upgrade/0]).

%% supervisor callbacks
-export([init/1]).

%% @spec start_link() -> ServerRet
%% @doc API for starting the supervisor.
start_link() ->
    % 创建一个监控进程
    supervisor:start_link({local, ?MODULE}, ?MODULE, []).

%% @spec init([]) -> SupervisorTree
%% @doc supervisor callback.
init([]) ->
    Web = web_specs(yzb_web, 8080),
    Processes = [Web],
    % 监控树类型：
    % one-for-one : 如果一个进程失效， 它的监控进程就会重启它
    % all-for-one : 如果一个进程失效， 所有的工作进程都会被终止（terminate/2），然后所有的
    %               工作进程又重新启动。
    % 10毫秒你内最多重启10次
    Strategy = {one_for_one, 10, 10},
    
    %lists:flatten(Processes)
    %[{yzb_web,
    %    {   yzb_web,start,
    %        [[
    %          {ip,{127,0,0,1}},
    %          {port,8080},
    %          {docroot,"/home/jobin/work/erlang/yzb/priv/www"}
    %        ]]
    %    },
    %    permanent：永久进程，5000:终止时间，worker：工作进程
    %    dynamic
    %    permanent,5000,worker,dynamic}]
    
    %   {Id, StartFunc, Restart, Shutdown, Type, Modules}
    %   Id = term()
    %   StartFunc = {M, F, A}
    %   M = F = atom()
    %   A = [term()]
    %   Restart = permanent | transient | temporary
    %   Shutdown = brutal_kill | integer() &gt;=0 | infinity
    %   Type = worker | supervisor
    %   Modules = [Module] | dynamic
    %   Module = atom()
    %   Id用来内部标识子规范
    %   StartFunc是启动子进程时调用的函数，它将成为对supervisor:start_link, gen_server:start_link, gen_fsm:start_link or gen_event:start_link的调用
    %   Restart标识一个进程终止后将怎样重启，一个permanent 进程总会被重启；一个temporary 进程从不会被重启；一个transient 进程仅仅当是不正常的被终止后才重启，例如非normal得退出原因
    %   Shutdown 定义一个进程将怎样被终止，brutal_kill意味着子进程被exit(Child, kill)无条件的终止；一个整数值的超时时间意味着监督者告诉子进程通过调用exit(Child, shutdown)而被终止，然后等待一个返回的退出信号，假如在指定的时间里没有收到退出信号，那么子进程用exit(Child, kill)被无条件终止。
    %   Type指定子进程是supervisor还是worker
    %   Modules 是有一个元素的列表[Module]，假如子进程是supervisor、gen_server 或 gen_fsm，那么Module 是回调模块的名称；假如子进程是gen_event，那么Modules 应该是dynamic
    
    {ok,
    % lists:flatten ： 进行扁平化处理(++) 转换成列表
     {Strategy, lists:flatten(Processes)}}.

web_specs(Mod, Port) ->
    WebConfig = [{ip, {127,0,0,1}},
                 {port, Port},
                 {docroot, yzb_deps:local_path(["priv", "www"])}],
    {Mod,
     {Mod, start, [WebConfig]},
     permanent, 5000, worker, dynamic}.

%% @spec upgrade() -> ok
%% @doc Add processes if necessary.
upgrade() ->
    {ok, {_, Specs}} = init([]),

    Old = sets:from_list(
            [Name || {Name, _, _, _} <- supervisor:which_children(?MODULE)]),
    New = sets:from_list([Name || {Name, _, _, _, _, _} <- Specs]),
    Kill = sets:subtract(Old, New),

    sets:fold(fun (Id, ok) ->
                      supervisor:terminate_child(?MODULE, Id),
                      supervisor:delete_child(?MODULE, Id),
                      ok
              end, ok, Kill),

    [supervisor:start_child(?MODULE, Spec) || Spec <- Specs],
    ok.
